#include "../../_ui/ShoppingUI.j"


// 怪物系统
library MonsterVo initializer init requires GameData, UIFunction

    globals
        // 每波需要创建的怪物数量
        constant integer MONSTER_PER_WAVE = 80

        // 准备阶段时间
        constant integer PREPARE_TIME = 10

        // 指定波数的怪物数量
        integer array monsterCount

        // 当前波数
        integer monster_wave = 1
        // 当前波数怪物死亡的数量
        integer monsterDeadCount = 0

        // 当前游戏状态// 0未开始 1进行中 2准备阶段 
        integer gmState = 0

        // 玩家游戏状态 0未开始 1进行中(已准备) 2准备阶段
        integer array playerGmState

        // 存储创建的怪物(当前怪物的数量，怪物)
        hashtable gwHash = InitHashtable()

    endglobals

    // 给当前怪物池子添加怪物
    function addMonsterToPool takes unit u returns nothing
        // 父0中存储一些信息
        local integer count = LoadInteger(gwHash, 0, 1) + 1
        // 子1总存储当前使用的最大数量，只有添加的单位的时候增加，删除的时候不减少，用于循环判断所有单位使用
        call SaveInteger(gwHash, 0, 1, count)
        // 子2存储真实的数量，真实数量为0的时候可以清空hash表
        call SaveInteger(gwHash, 0, 2, count)

        // 父1中存储怪物
        call SaveUnitHandle(gwHash, 1, count, u)

        // 存储怪物对应的id
        call SaveInteger(gwHash, GetHandleId(u), 0, count)
    endfunction
    // 获取怪物池子中的数量
    function getMonsterPoolCount takes nothing returns integer
        return LoadInteger(gwHash, 0, 1)
    endfunction
    // 获取怪物池子中真实的怪物数量
    function getRealMonsterPoolCount takes nothing returns integer
        return LoadInteger(gwHash, 0, 2)
    endfunction
    // 获取指定id的怪物
    function getMonsterById takes integer id returns unit
        return LoadUnitHandle(gwHash, 1, id)
    endfunction

    // 从怪物池子中删除怪物
    function removeMonsterFromPool takes unit u returns nothing
        local integer count = LoadInteger(gwHash, 0, 2) - 1
        call SaveInteger(gwHash, 0, 2, count)

        if count <= 0 then
            // 清空hash表
            call FlushParentHashtable(gwHash)
        else
            // 从hash删除怪物
            call RemoveSavedHandle(gwHash, 1, LoadInteger(gwHash, GetHandleId(u), 0))
            // 删除怪物对应的id
            call RemoveSavedInteger(gwHash, GetHandleId(u), 0)
        endif
    endfunction

    // 获取要被怪物攻击的英雄单位
    // 存活英雄谁的距离最近就攻击谁
    function getHeroToAttack takes unit monster returns unit
        local integer uid = 0
        local real dis = getDistance(GetUnitX(monster), GetUnitY(monster), GetUnitX(udg_player_select_hero[uid]), GetUnitY(udg_player_select_hero[uid]))
        local real v
        local integer i = 0
        loop
            exitwhen uid > PLAYER_NUMBER
            if udg_player_select_hero[uid] != null and FF_GetHp(udg_player_select_hero[uid]) >= 1.0 then
                set v = getDistance(GetUnitX(monster), GetUnitY(monster), GetUnitX(udg_player_select_hero[uid]), GetUnitY(udg_player_select_hero[uid]))
                if v < dis then
                    set i = uid
                    set dis = v
                endif
            endif
            set uid = uid + 1
        endloop
        return udg_player_select_hero[i]
    endfunction

    // 每秒给怪物发送攻击指令
    function Second_MonsAttack takes nothing returns nothing
        local integer i = 1
        local integer count = getMonsterPoolCount()
        local unit u = null
        local unit monster = null
        local real x
        local real y

        loop
            exitwhen i > count
            
            set monster = getMonsterById(i)
            if monster != null then
                set u = getHeroToAttack(monster)
                // call IssuePointOrder( monster, "move", GetUnitX(u), GetUnitY(u) )
                // call IssuePointOrder( monster, "attackground", GetUnitX(u), GetUnitY(u) )

                // 根据坐标判断是否卡怪
                set x = GetUnitX(monster)
                set y = GetUnitY(monster)
                if x == FF_GetUnitX(monster) and y == FF_GetUnitY(monster) then
                    call IssuePointOrder( monster, "attack", GetUnitX(u), GetUnitY(u) )
                endif
                // 重新刷新坐标
                call FF_SetUnitX(monster, x)
                call FF_SetUnitY(monster, y)
            endif
            set i = i + 1
        endloop
        set u = null
        set monster = null
    endfunction


    // 创建指定波数的怪物
    function createMonsterByWave takes integer wave returns nothing
        local unit u
        local integer i = 0
        local real x
        local real y

        local string array mdls
        set mdls[1] = "units\\human\\Footman\\Footman.mdl"
        set mdls[2] = "units\\human\\Knight\\Knight.mdl"
        set mdls[3] = "units\\orc\\Grunt\\Grunt.mdl"
        set mdls[4] = "units\\orc\\Tauren\\Tauren.mdl"
        set mdls[5] = "units\\undead\\CryptFiend\\CryptFiend.mdl"


        loop
            exitwhen i >= MONSTER_PER_WAVE
            set x = GetRectRandomX(getMonsterCenterRect())
            set y = GetRectRandomY(getMonsterCenterRect())
            set u = createUByProperty('h003', 10001, 0, "名字", x, y, 270.0, I2R(100 * wave), I2R(100 * wave), 50, 100, 100, 100, 100, 100, 100, 100, mdls[wave], 1, 0)
            call FF_SetUnitWave(u, wave)
            call FF_SetUnitX(u, x)
            call FF_SetUnitY(u, y)
            
            // call SetUnitPathing( u, false )
            call addMonsterToPool(u)

            set i = i + 1
        endloop

        set u = null
    endfunction

    // 开始游戏
    function startGame takes nothing returns nothing
        local integer uid = 0
        // 设置游戏状态
        set gmState = 1

        // TODO 隐藏全部UI
        call UI_hide_shopping()
        call UI_hide_ready()

        // 设置玩家游戏状态
        loop
            exitwhen uid > PLAYER_NUMBER
            set playerGmState[uid] = 1
            set uid = uid + 1
        endloop
        // 创建怪物
        call createMonsterByWave(monster_wave)
    endfunction

    // 获取准备玩家的数量
    function getReadyPlayerCount takes nothing returns integer
        local integer count = 0
        local integer uid = 0
        loop
            exitwhen uid > PLAYER_NUMBER
            if isPlayerOnline(uid) then
                set count = count + 1
            endif
            set uid = uid + 1
        endloop

        return count
    endfunction

    // 玩家点击准备
    function playerReady takes integer uid returns nothing
        // 设置准备状态
        set playerGmState[uid] = 2

        // 所有玩家点击了准备则开始游戏
        if getOnlinePlayerCount() == getReadyPlayerCount() then
            call startGame()
        endif
    endfunction

    function timer_ready takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer tid = GetHandleId(t)
        local integer uid = 0

        call SaveInteger(gameht, tid, 1, LoadInteger(gameht, tid, 1) + 1)
        // 设置UI时间显示
        loop
            exitwhen uid > PLAYER_NUMBER
            if gmState == 2 then
                // 表示该玩家已经准备
                if playerGmState[uid] == 1 then
                    // 设置为已准备
                    if Player(uid) == GetLocalPlayer() then
                        call DzFrameSetText( LoadInteger(UI_HASH, StringHash("准备UI"), 101), "|cff00ff00已准备|r" )
                    endif
                elseif playerGmState[uid] == 2 then
                    // 设置倒计时显示
                    if Player(uid) == GetLocalPlayer() then
                        call DzFrameSetText( LoadInteger(UI_HASH, StringHash("准备UI"), 101), "准备（|cff00ff00" + I2S(PREPARE_TIME - LoadInteger(gameht, tid, 1)) + "|r）" )
                    endif
                endif
            endif
            set uid = uid + 1
        endloop

        if LoadInteger(gameht, tid, 1) >= PREPARE_TIME then 
            call DestroyTimer(t)
            call FlushChildHashtable(gameht, tid)

            // 如果游戏没开始，开始游戏，表示不是通过玩家准备来开始游戏的
            if gmState == 2 then
                call startGame()
            endif
        endif

        set t = null
    endfunction
    // 一波结束进入准备阶段
    private function ready takes nothing returns nothing
        local integer uid = 0
        local timer t = CreateTimer()

        set gmState = 2
        // 设置玩家游戏状态
        loop
            exitwhen uid > PLAYER_NUMBER
            set playerGmState[uid] = 2
            set uid = uid + 1
        endloop

        // TODO 显示UI，后期可优化动态效果
        call UI_show_shopping()
        call UI_show_ready()

        // 计时器倒计10秒
        call TimerStart(t, 1.0, true, function timer_ready)
    endfunction

    // 怪物死亡
    function MonsterVo_die takes unit u, unit bu returns nothing
        local integer uid = GetPlayerId(GetOwningPlayer(u))

        set monsterDeadCount = monsterDeadCount + 1
        // call BJDebugMsg("monsterDeadCount = " + I2S(monsterDeadCount))

        // 从池中清空
        call removeMonsterFromPool(bu)

        // 表示杀完了当前所有怪
        if monsterCount[monster_wave] == monsterDeadCount then
            set monsterDeadCount = 0
            // 波数增加
            set monster_wave = monster_wave + 1

            call BJDebugMsg("==== 进入下"+ I2S(monster_wave) +"波")
            // 进入准备阶段
            call ready()
        endif

        call FF_DestroyUnitPro(bu)
    endfunction

    private function init takes nothing returns nothing

        local integer wave = 1
        loop
            exitwhen wave > 100

            set monsterCount[wave] = MONSTER_PER_WAVE
            
            set wave = wave + 1
        endloop

        call startGame()
    endfunction
endlibrary


